package org.pblue.tumblarity.tools;

import static com.google.appengine.api.urlfetch.FetchOptions.Builder.doNotFollowRedirects;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.List;
import java.util.logging.Logger;

import org.pblue.armyknife.Utils;

import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

public class TumblrHttpTools {
  
  public static final String URL_TUMBLR = "http://www.tumblr.com";
  public static final String ENCODING_LOGIN = "UTF-8";
  public static final String URI_LOGIN = "/login";
  public static final String URI_PAGE = "/followers/page/{0}";
  public static final String URI_PAGE_WITH_TUMBLELOG = "/tumblelog/{1}/followers/page/{0}";
  public static final String PARAMETER_EMAIL = "email";
  public static final String PARAMETER_PASSWORD = "password";
  public static final String CONTENT_INVALID_LOGIN = "Email or password is incorrect";
  public static final String CONTENT_TUMBLELOG_NOT_EXIST = "Not found.";
  public static final String CONTENT_NEXT_PAGE = "Next page";
  public static final String CONTENT_PREVIOUS_PAGE = "Previous page";
  public static final String CONTENT_0_FOLLOWERS = ".*([^0-9]0 people are following you).*";
  
  private static URLFetchService mURLFetchServiceInstance;
  
  private static final Logger log = Logger.getLogger(TumblrHttpTools.class.getName());
  
  public static String getPage(String pEmail, String pTumblelog, String pPassword, int pPage) throws IOException {
    String url = MessageFormat.format(URI_PAGE, new Object[] { pPage });
    if (pTumblelog != null && !pTumblelog.equals("")) {
      url = MessageFormat.format(URI_PAGE_WITH_TUMBLELOG, new Object[] { pPage, pTumblelog });
    }
    
    URL pageURL = new URL(URL_TUMBLR + url);
    HTTPRequest pageRequest = new HTTPRequest(pageURL, HTTPMethod.GET, doNotFollowRedirects().disallowTruncate());
    HTTPResponse pageResponse = getFetchService().fetch(pageRequest);
    
    if (pageResponse.getResponseCode() >= 300) {
      LoginBean loginBean = login(pEmail, pPassword);
      if (!loginBean.isSuccesful()) {
        log.severe("Login to Tumblr has failed.");
        return null;
      }
      HTTPHeader cookies = new HTTPHeader("Cookie", loginBean.getAuthenticationCookie());
      pageRequest.addHeader(cookies);
      pageResponse = getFetchService().fetch(pageRequest);
    }
    
    return new String(pageResponse.getContent());
  }
  
  public static boolean tumblelogExists(String pEmail, String pTumblelog, String pPassword) throws IOException {
    String resp = getPage(pEmail, pTumblelog, pPassword, 1);
    return resp != null ? resp.indexOf(CONTENT_TUMBLELOG_NOT_EXIST) == -1 : false;
  }
  
  public static LoginBean login(String pEmail, String pPassword) throws IOException {
    LoginBean loginBean = new LoginBean();
    String body = PARAMETER_EMAIL + "=" + URLEncoder.encode(pEmail,ENCODING_LOGIN) + "&" + PARAMETER_PASSWORD + "=" + URLEncoder.encode(pPassword,ENCODING_LOGIN);
    URL loginURL = new URL(URL_TUMBLR + URI_LOGIN);
    HTTPRequest loginRequest = new HTTPRequest(loginURL, HTTPMethod.POST);
    loginRequest.setPayload(body.getBytes());

    HTTPResponse loginResponse = TumblrHttpTools.getFetchService().fetch(loginRequest);
    String resp = new String(loginResponse.getContent());
    
    loginBean.setSuccesful(resp.indexOf(CONTENT_INVALID_LOGIN) == -1);
    loginBean.setAuthenticationCookie(TumblrHttpTools.getAuthenticationString(loginResponse));
    
    return loginBean;
  }
  
  private static final String LOGIN_PATTERN_TMGIOCT = "tmgioct={0};";
  private static final String LOGIN_PATTERN_PFU = "pfu={0};";
  private static final String LOGIN_PATTERN_PFP = "pfp={0};";
  private static final String LOGIN_PATTERN_PFE = "pfe={0};";
  private static final String LOGIN_AUTH_HEADER_NAME = "set-cookie";
  
  private static String getAuthenticationString(HTTPResponse pResponse) {
    String cookies = "";
    
    List<HTTPHeader> headers = pResponse.getHeaders();
    for (HTTPHeader header : headers) {
      if (header.getName().toLowerCase().equals(LOGIN_AUTH_HEADER_NAME)) {
        cookies = header.getValue();
      }
    }
    
    String tmgioct = Utils.matchPattern(cookies, MessageFormat.format(LOGIN_PATTERN_TMGIOCT, new Object[] { "(.*?)" }));
    tmgioct = tmgioct != null && !tmgioct.equals("") ? MessageFormat.format(LOGIN_PATTERN_TMGIOCT, new Object[] { tmgioct }) : null;
    
    String pfu = Utils.matchPattern(cookies, MessageFormat.format(LOGIN_PATTERN_PFU, new Object[] { "(.*?)" }));
    pfu = pfu != null && !pfu.equals("") ? MessageFormat.format(LOGIN_PATTERN_PFU, new Object[] { pfu }) : null;
    
    String pfp = Utils.matchPattern(cookies, MessageFormat.format(LOGIN_PATTERN_PFP, new Object[] { "(.*?)" }));
    pfp = pfp != null && !pfp.equals("") ? MessageFormat.format(LOGIN_PATTERN_PFP, new Object[] { pfp }) : null;
    
    String pfe = Utils.matchPattern(cookies, MessageFormat.format(LOGIN_PATTERN_PFE, new Object[] { "(.*?)" }));
    pfe = pfe != null && !pfe.equals("") ? MessageFormat.format(LOGIN_PATTERN_PFE, new Object[] { pfe }) : null;
    
    if (tmgioct != null && pfu != null && pfp != null && pfe != null) {
      return tmgioct + " " + pfu + " " + pfp + " " + pfe;
    }
    
    return null;
  }
  
  public static URLFetchService getFetchService() {
    if (mURLFetchServiceInstance == null) {
      mURLFetchServiceInstance = URLFetchServiceFactory.getURLFetchService();
    }
    return mURLFetchServiceInstance;
  }
  
}
